package serialize;

import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.sun.istack.internal.Nullable;

import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description:
 * @author: fengrun@pinduoduo.com
 * @date: 2018/9/11
 */
public class BaseModel {
    private static final String TAG = "BaseModel";
    private static final String QUERY_AND = "&";
    private static final String QUERY_VALUE = "=";
    private static final String UTF8 = "UTF-8";
    private static final String SERIAL_VERSION_UID = "serialVersionUID";

    public BaseModel() {}

    public String toJson() {
        return new Gson().toJson(this);
    }

    public String toJson(@Nullable String[] reqIgnoreFields) {
        if (reqIgnoreFields == null) {
            return toJson();
        }
        Map<String, Object> jsonMap = toRestful();
        for (String ignoreField : reqIgnoreFields) {
            jsonMap.remove(ignoreField);
        }
        return new Gson().toJson(jsonMap);
    }

    /***
     * toQuery 只处理简单Object(内部成员变量都是基础类型)
     * @return 返回形如 "a=1&b=x"
     */
    public String toQuery(@Nullable String[] reqIgnoreFields) {
        StringBuilder query = new StringBuilder();
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
//            if (!field.getType().getPackage().getName().equals("java.lang")) {
//                continue;
//            }
            if (field == null) {
                continue;
            }
            field.setAccessible(true);
            String fieldName = field.getName();
            SerializedName alterName;
            alterName = field.getAnnotation(SerializedName.class);
            if (alterName != null) {
                fieldName = alterName.value();
            }

            try {
                Object value = field.get(this);
                if (value == null || filterField(fieldName)
                    || filterFields(reqIgnoreFields, fieldName)) {
                    continue;
                }

                if (query.length() != 0) {
                    query.append(QUERY_AND);
                }
                String encode = URLEncoder.encode(value.toString(), UTF8);
                query.append(fieldName).append(QUERY_VALUE).append(encode);
            } catch (Throwable tr) {
                // Log.printErrorStackTrace(TAG, "toQuery", tr);
            }
        }
        return query.toString();
    }

    public Map<String, Object> toRestful() {

        Field[] fields = this.getClass().getDeclaredFields();
        Map<String, Object> map = new HashMap<>(fields.length);
        for (Field field : fields) {
//            if (!field.getType().getClass().getPackage().getName().equals("java.lang")) {
//                continue;
//            }
            if (field == null) {
                continue;
            }

            field.setAccessible(true);
            String fieldName = field.getName();
            SerializedName alterName;
            alterName = field.getAnnotation(SerializedName.class);
            if (alterName != null) {
                fieldName = alterName.value();
            }

            try {
                Object value = field.get(this);
                if (value == null || filterField(fieldName)) {
                    continue;
                }
                map.put(fieldName, value);

            } catch (Throwable tr) {
                // Log.printErrorStackTrace(TAG, "toRestful", tr);
            }
        }

        return map;
    }

    private boolean filterField(String fieldName) {
        return  SERIAL_VERSION_UID.equals(fieldName);
    }

    private boolean filterFields(String[] filters, String fieldName) {
        if (filters == null) {
            return false;
        }
        List<String> copys = Arrays.asList(filters);
        return  copys.indexOf(fieldName) >= 0;
    }

    @Override
    public String toString() {
        return toJson();
    }
}
